﻿#pragma once

#include <functional>
namespace lh
{
	template<class T>
	class shared_ptr
	{
	public:
		template<class D>
		shared_ptr(T* ptr,D del)
			:_ptr(ptr)
			, _pcount(new int(1))
			,_del(del)
		{
		}
		// RAII
		shared_ptr(T* ptr=nullptr)
			:_ptr(ptr)
			,_pcount(new int(1))
		{ }

		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			,_pcount(sp._pcount)
		{
			++(*_pcount);
		}
		
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (_ptr != sp._ptr)
			{
				//检测是否有其他对象共享该份资源
				release();

			    _ptr = sp._ptr;
			    _pcount = sp._pcount;
			    ++(*_pcount);
			}

			return *this;
		}

		void release()
		{
			--(*_pcount);
			if ((*_pcount) == 0)
			{
				_del(_ptr);
				delete _pcount;
			}
		}

		~shared_ptr()
		{
			release();
		}
		
		// 重载运算符，模拟指针的⾏为，⽅便访问资源
		T& operator*()
		{
			return *_ptr;
		}
		
		T* operator->()
		{
			return _ptr;
		}
		
		T& operator[](size_t i)
		{
			return _ptr[i];
		}

		T* get()
		{
			return _ptr;
		}

		int use_count()
		{
			return *_pcount;
		}

		operator bool()
		{
			return _ptr != nullptr;
		}
	private:
		T* _ptr;
		int* _pcount;
		function<void(T*)> _del = [](T* ptr) {
			delete ptr;
	    };
	};
}
